package service

import (
	"errors"

	"GinAdmin/core/database"
	"GinAdmin/model"

	"gorm.io/gorm"
)

// RoleService 角色服务
type RoleService struct {
	db *gorm.DB
}

// NewRoleService 创建角色服务
func NewRoleService() *RoleService {
	return &RoleService{
		db: database.DB,
	}
}

// GetRoleByID 根据ID获取角色
func (s *RoleService) GetRoleByID(id uint) (*model.Role, error) {
	var role model.Role
	if err := s.db.Preload("Menus").First(&role, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("角色不存在")
		}
		return nil, err
	}
	return &role, nil
}

// GetRoleList 获取角色列表
func (s *RoleService) GetRoleList(params *model.RoleSearchParams) ([]model.Role, int64, error) {
	var roles []model.Role
	var total int64

	query := s.db.Model(&model.Role{})

	if params.Name != "" {
		query = query.Where("name LIKE ?", "%"+params.Name+"%")
	}

	if params.Code != "" {
		query = query.Where("code LIKE ?", "%"+params.Code+"%")
	}

	if params.Status != 0 {
		query = query.Where("status = ?", params.Status)
	}

	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	if err := query.Preload("Menus").Find(&roles).Error; err != nil {
		return nil, 0, err
	}

	return roles, total, nil
}

// CreateRole 创建角色
func (s *RoleService) CreateRole(req *model.CreateRoleRequest) (*model.Role, error) {
	// 检查角色编码是否存在
	var count int64
	if err := s.db.Model(&model.Role{}).Where("code = ?", req.Code).Count(&count).Error; err != nil {
		return nil, err
	}
	if count > 0 {
		return nil, errors.New("角色编码已存在")
	}

	role := model.Role{
		Name:   req.Name,
		Code:   req.Code,
		Sort:   req.Sort,
		Status: req.Status,
		Remark: req.Remark,
	}

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	if err := tx.Create(&role).Error; err != nil {
		tx.Rollback()
		return nil, err
	}

	// 关联菜单
	if len(req.MenuIDs) > 0 {
		var menus []model.Menu
		if err := tx.Where("id IN ?", req.MenuIDs).Find(&menus).Error; err != nil {
			tx.Rollback()
			return nil, err
		}
		if err := tx.Model(&role).Association("Menus").Replace(menus); err != nil {
			tx.Rollback()
			return nil, err
		}
	}

	if err := tx.Commit().Error; err != nil {
		return nil, err
	}

	return &role, nil
}

// UpdateRole 更新角色
func (s *RoleService) UpdateRole(id uint, req *model.UpdateRoleRequest) (*model.Role, error) {
	var role model.Role
	if err := s.db.First(&role, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("角色不存在")
		}
		return nil, err
	}

	// 检查角色编码是否已存在（如果更新了编码）
	if req.Code != "" && req.Code != role.Code {
		var count int64
		if err := s.db.Model(&model.Role{}).Where("code = ? AND id != ?", req.Code, id).Count(&count).Error; err != nil {
			return nil, err
		}
		if count > 0 {
			return nil, errors.New("角色编码已存在")
		}
	}

	// 构造更新数据
	updates := make(map[string]interface{})
	if req.Name != "" {
		updates["name"] = req.Name
	}
	if req.Code != "" {
		updates["code"] = req.Code
	}
	updates["sort"] = req.Sort
	if req.Status != 0 {
		updates["status"] = req.Status
	}
	if req.Remark != "" {
		updates["remark"] = req.Remark
	}

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	if len(updates) > 0 {
		if err := tx.Model(&role).Updates(updates).Error; err != nil {
			tx.Rollback()
			return nil, err
		}
	}

	// 更新菜单关联
	if len(req.MenuIDs) > 0 {
		var menus []model.Menu
		if err := tx.Where("id IN ?", req.MenuIDs).Find(&menus).Error; err != nil {
			tx.Rollback()
			return nil, err
		}
		if err := tx.Model(&role).Association("Menus").Replace(menus); err != nil {
			tx.Rollback()
			return nil, err
		}
	}

	if err := tx.Commit().Error; err != nil {
		return nil, err
	}

	// 重新加载角色信息
	if err := s.db.Preload("Menus").First(&role, id).Error; err != nil {
		return nil, err
	}

	return &role, nil
}

// DeleteRole 删除角色
func (s *RoleService) DeleteRole(id uint) error {
	// 检查是否有用户关联此角色
	var count int64
	if err := s.db.Table("go_user_role").Where("role_id = ?", id).Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return errors.New("该角色已关联用户，无法删除")
	}

	var role model.Role
	if err := s.db.First(&role, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("角色不存在")
		}
		return err
	}

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 清除菜单关联
	if err := tx.Model(&role).Association("Menus").Clear(); err != nil {
		tx.Rollback()
		return err
	}

	// 删除角色
	if err := tx.Delete(&role).Error; err != nil {
		tx.Rollback()
		return err
	}

	return tx.Commit().Error
}

// GetRoleMenus 获取角色菜单
func (s *RoleService) GetRoleMenus(id uint) ([]model.Menu, error) {
	var role model.Role
	if err := s.db.Preload("Menus").First(&role, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("角色不存在")
		}
		return nil, err
	}
	return role.Menus, nil
}

// UpdateRoleMenus 更新角色菜单
func (s *RoleService) UpdateRoleMenus(id uint, menuIDs []uint) error {
	var role model.Role
	if err := s.db.First(&role, id).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("角色不存在")
		}
		return err
	}

	// 开始事务
	tx := s.db.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 清除之前的菜单关联
	if err := tx.Model(&role).Association("Menus").Clear(); err != nil {
		tx.Rollback()
		return err
	}

	// 如果有新的菜单ID，关联新菜单
	if len(menuIDs) > 0 {
		var menus []model.Menu
		if err := tx.Where("id IN ?", menuIDs).Find(&menus).Error; err != nil {
			tx.Rollback()
			return err
		}
		if err := tx.Model(&role).Association("Menus").Replace(menus); err != nil {
			tx.Rollback()
			return err
		}
	}

	return tx.Commit().Error
}
